package 反射;

import org.junit.Test;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

/*
    获取运行时类的完整结构(Field、Method、Constructor、Superclass、Interface、Annotation)
         实现的全部接口
         所继承的父类
         全部的构造器
         全部的方法
         全部的Field

    使用反射可以取得:
        1.实现的全部接口
             public Class<?>[] getInterfaces()
          确定此对象所表示的类或接口实现的接口
        2.所继承的父类
            public Class<? Super T> getSuperclass()
          返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class
        3.全部的构造器
             public Constructor<T>[] getConstructors()
              返回此 Class 对象所表示的类的所有public构造方法
             public Constructor<T>[] getDeclaredConstructors()
              返回此 Class 对象表示的类声明的所有构造方法
            Constructor类中:
                 取得修饰符:public int getModifiers()
                 取得方法名称:public String getName()
                 取得参数的类型:public Class<?>[] getParameterTypes()
        4.全部的方法
             public Method[] getDeclaredMethods()
            返回此Class对象所表示的类或接口的全部方法
             public Method[] getMethods()
            返回此Class对象所表示的类或接口的public的方法
            Method 类中:
                 public Class<?> getReturnType():取得全部的返回值
                 public Class<?>[] getParameterTypes():取得全部的参数
                 public int getModifiers():取得修饰符
                 public Class<?>[] getExceptionTypes():取得异常信息
        5.全部的Field
             public Field[] getFields()
            返回此Class对象所表示的类或接口的public的Field
            public Field[] getDeclaredFields()
            返回此Class对象所表示的类或接口的全部Field
            Field 方法中:
                 public int getModifiers():以整数形式返回此Field的修饰符
                 public Class<?> getType():得到Field的属性类型
                 public String getName():返回Field的名称
        6.Annotation相关
             get Annotation(Class<T> annotationClass)
             getDeclaredAnnotations()
        7.泛型相关
             Type getGenericSuperclass()
            获取父类泛型类型
             ParameterizedType
            泛型类型
             getActualTypeArguments()
            获取实际的泛型类型参数数组
        8.Package getPackage():类所在的包
    注:
         在实际的操作中,取得类的信息的操作代码,并不会经常开发
         一定要熟悉java.lang.reflect包的作用,反射机制
         如何取得属性、方法、构造器的名称,修饰符等
 */
public class Class06 {

    //获取当前运行时类的属性结构
    @Test
    public void FieldTest01(){
        Class<People> clazz = People.class;

        /*
            getFields():获取当前运行时类及其父类中声明为public访问权限的属性
         */
        Field[] fields = clazz.getFields();
        for(Field field : fields){
            System.out.println(field);
        }

        System.out.println("*********************");

        /*
            getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类中声明的属性,且与当前类的修饰符无关)
         */
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field field : declaredFields){
            System.out.println(field);
        }
    }

    //获取当前运行时类的属性具体的结构
    @Test
    public void FieldTest02(){
        Class<People> clazz = People.class;

        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field field : declaredFields){

            //权限修饰符
            int modifier = field.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");

            //数据类型
            Class<?> type = field.getType();
            System.out.print(type.getName() + "\t");

            //变量名
            String fieldName = field.getName();
            System.out.print(fieldName);

            System.out.println();
        }
    }

    //获取当前运行时类的方法结构
    @Test
    public void MethodTest03(){
        Class<People> peopleClass = People.class;

        /*
            getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
         */
        Method[] methods = peopleClass.getMethods();
        for(Method method : methods){
            System.out.println(method);
        }

        System.out.println("*********************");

        /*
            getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中声明的方法,且与当前类的修饰符无关)
         */
        Method[] declaredMethods = peopleClass.getDeclaredMethods();
        for(Method method : declaredMethods){
            System.out.println(method);
        }
    }

    //获取当前运行时类的方法具体的结构
    @Test
    public void MethodTest04(){
        Class<People> peopleClass = People.class;

        Method[] declaredMethods = peopleClass.getDeclaredMethods();
        for(Method method : declaredMethods){
            //获取方法中声明的注解
            Annotation[] annotations = method.getAnnotations();
            for(Annotation annotation : annotations){
                System.out.print(annotation + "\t");
            }

            //获取方法中声明的权限修饰符
            System.out.print(Modifier.toString(method.getModifiers()) + "\t");

            //获取方法中声明的返回值类型
            System.out.print(method.getReturnType().getName() + "\t");

            //获取方法中声明的方法名
            System.out.print(method.getName());

            //获取方法中声明的形参列表
            System.out.print("(");
            Class<?>[] parameterTypes = method.getParameterTypes();
            if(!(parameterTypes == null || parameterTypes.length == 0)){
                for(int i = 0; i < parameterTypes.length; i++){
                    if(i == parameterTypes.length - 1){
                        System.out.print(parameterTypes[i].getName() + " args_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + " args_" + i + ",");

                }
            }
            System.out.print(")");

            //获取方法中抛出的异常
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            if(!(exceptionTypes == null || exceptionTypes.length == 0)){
                System.out.print("throws ");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if(i == exceptionTypes.length - 1){
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ",");
                }
            }

            System.out.println();
        }
    }

    //获取当前运行时类的构造器结构
    @Test
    public void ConstructorTest05(){
        Class<People> peopleClass = People.class;

        /*
            getConstructors():获取当前运行时类中声明为public的构造器
         */
        Constructor<?>[] constructors = peopleClass.getConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        System.out.println("*********************");

        /*
            getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
         */
        Constructor<?>[] declaredConstructors = peopleClass.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors){
            System.out.println(constructor);
        }
    }

    //获取当前运行时类的父类
    @Test
    public void ParentTest06(){
        Class<People> peopleClass = People.class;

        //获取当前运行时类的父类
        Class<? super People> superclass = peopleClass.getSuperclass();
        System.out.println(superclass);

        //获取当前运行时类的带泛型的父类
        Type genericSuperclass = peopleClass.getGenericSuperclass();
        System.out.println(genericSuperclass);

        //获取当前运行时类的带泛型的父类的泛型
        ParameterizedType paramType = (ParameterizedType)genericSuperclass;
        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        for(Type type : actualTypeArguments){
            System.out.println(type.getTypeName());
        }
    }

    //获取当前运行时类实现的接口
    @Test
    public void InterfaceTest07(){
        Class<People> peopleClass = People.class;

        /*
            getInterfaces():获取当前运行时类实现的接口
         */
        Class<?>[] interfaces = peopleClass.getInterfaces();
        for(Class clazz : interfaces){
            System.out.println(clazz);
        }

        System.out.println("*********************");

        //获取当前运行时类父类实现的接口
        Class<?>[] superInterfaces = peopleClass.getSuperclass().getInterfaces();
        for(Class clazz : superInterfaces){
            System.out.println(clazz);
        }
    }

    //获取当前运行时类所在的包
    @Test
    public void PackageTest08(){
        Class<People> peopleClass = People.class;

        Package pack = peopleClass.getPackage();
        System.out.println(pack);
    }

    //获取当前运行时类声明的注解
    @Test
    public void AnnotationTest09(){
        Class<People> peopleClass = People.class;

        Annotation[] annotations = peopleClass.getAnnotations();
        for(Annotation annotation : annotations){
            System.out.println(annotation);
        }
    }
}




class Creature<T> implements Serializable {

    private char gender;
    public double weight;

    private void breath(){
        System.out.println("人呼吸");
    }

    public void eat(){
        System.out.println("人吃东西");
    }
}

interface MyInterface{
    void info();
}

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    String value() default "hello";
}

@MyAnnotation("hi")
class People extends Creature<String> implements Comparable<String>,MyInterface{

    private String name;
    int age;
    public int id;

    public People(){}

    @MyAnnotation("abc")
    private People(String name){
        this.name = name;
    }

    People(String name,int age){
        this.name = name;
        this.age = age;
    }

    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国籍是:" + nation);
        return nation;
    }

    public String display(String interests,int age) throws RuntimeException,ClassCastException{
        return interests + age;
    }

    private static void showDesc(){
        System.out.println("静态方法");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}
